/*
 * InputCalculator.java Created on Feb 16, 2003 11:05:00 AM
 *
 * Copyright (C) 2003 eRocX Software Group - www.erocx.com
 */
package com.erocx.c24;

/**
 * <p>Title: InputCalculator</p>
 * <p>Description: calculate a input string </p>
 * 
 * @author		<a href="mailto:eroclu@gmail.com">Andy Lu</a>
 * @version   	1.0
 */

public final class InputCalculator {

    public InputCalculator() {
    }

    public double calculate(String text) throws Exception {
        if (text == null)
            return 0.0;

        double result = 0.0;
        String filtered = filterBlanks(text);
        CellData cellData = parseString(filtered);
        String operandA = cellData.getOperandA();
        String operandB = cellData.getOperandB();
        char operator = cellData.getOperator();

        double a, b;

        if (isOperand(operandA) && isOperand(operandB)) {
            a = Double.parseDouble(operandA);
            b = Double.parseDouble(operandB);
        } else if (isOperand(operandA) && !isOperand(operandB)) {
            a = Double.parseDouble(operandA);
            b = calculate(operandB);
        } else if (!isOperand(operandA) && isOperand(operandB)) {
            a = calculate(operandA);
            b = Double.parseDouble(operandB);
        } else {
            a = calculate(operandA);
            b = calculate(operandB);
        }

        try {
            result = cal(a, b, operator);
        } catch (Exception e) {
            throw e;
        }


        return result;
    }

    private double cal(double a, double b, char operator) throws Exception {
            switch((char)operator) {
                case '+':
                    return a + b;
                case '-':
                    return a - b;
                case '*':
                    return a * b;
                case '/':
                    if (b != 0) {
                        return a / b;
                    } else { //divide overflow
                        throw new Exception();
                    }
                default:
                    throw new Exception();
            }
        }

    private CellData parseString(String text) {
        if (text == null)
            return null;

        String str = text.trim();
        int rightBracketPosition = getRightBracketPosition(str);
        if (str.charAt(0) == '(' && rightBracketPosition == (str.length() - 1)) {
            str = str.substring(1, str.length() - 1);
        }
        String operandA = null, operandB = null;
        char operator = ' ';

        String firstChar = str.substring(0, 1);
        int rightOperandPosition = getRightOperandPosition(str);
        rightBracketPosition = getRightBracketPosition(str);
        if (isOperand(firstChar)) {
            operandA = str.substring(0, rightOperandPosition + 1);
            operandB = str.substring(rightOperandPosition + 2, str.length());
            operator = str.charAt(rightOperandPosition + 1);
        }
        if (firstChar.equals("(")) {
            operandA = str.substring(0, rightBracketPosition + 1);
            operandB = str.substring(rightBracketPosition + 2, str.length());
            operator = str.charAt(rightBracketPosition + 1);
        }

        return new CellData(operandA, operandB, operator);
    }

    private String filterBlanks(String text) {
        if (text == null)
            return null;

        String str = text.trim();

        if (str.indexOf(" ") == -1)
            return str;

        String filtered = null;
        String left = str.substring(0, str.indexOf(" "));
        String right = str.substring(str.indexOf(" ") + 1, str.length());
        if (right.indexOf(" ") == -1) {
            filtered = left + right;
        } else {
            filtered = left + filterBlanks(right);
        }


        return filtered;
    }

    private int getRightOperandPosition(String text) {
        if (text == null)
            return -1;

        for (int i = 0; i < text.length(); i ++) {
            char c = text.charAt(i);
            if (c == '+' || c == '-' || c == '*' || c == '/')
                return i - 1;
        }
        return text.length();
    }

    private int getRightBracketPosition(String text) {
        if (text == null)
            return -1;

        int stack = 0;
        for (int i = 0; i < text.length(); i ++) {
            char c = text.charAt(i);
            if (c == '(') {
                stack ++;
            }
            if (c == ')') {
                stack --;
                if (stack == 0)
                    return i;
            }
        }

        return -1;
    }

    private boolean isOperand(String text) {
        if (text == null)
            return false;

        for (int i = 0; i < text.length(); i ++) {
            char c = text.charAt(i);

            if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')')
                return false;
        }
        return true;
    }

    private boolean isSimple(String text) {
        if (text == null)
            return false;

        int opAmout = 0;

        for (int i = 0; i < text.length(); i ++) {
            char c = text.charAt(i);
            if (c == '+' || c == '-' || c == '*' || c == '/')
                opAmout ++;
        }

        if (opAmout > 1)
            return false;
        else
            return true;
    }

    class CellData {
        private String operandA;
        private String operandB;
        private char operator;

        private double result;

        public CellData(String a, String b, char op) {
            operandA = a;
            operandB = b;
            operator = op;
        }

        public String getOperandA() {
            return operandA;
        }

        public String getOperandB() {
            return operandB;
        }

        public char getOperator() {
            return operator;
        }
    }

    public static void main(String[] args) {
        InputCalculator cal = new InputCalculator();
        try {
            //System.out.println(cal.calculate(" ( 1 + 3 ) * ( 2 + 4 ) "));
            //System.out.println(cal.calculate("(19-(1+8))*4"));
            System.out.println(cal.calculate("4+((1+9)*2)"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}